
`include "common_header.verilog"

//  *************************************************************************
//  File : rs_rx_64
//  *************************************************************************
//  This program is controlled by a written license agreement.
//  Unauthorized reproduction or use is expressly prohibited.
//  Copyright (c) 2014 MorethanIP
//  Muenchner Strasse 199, 85757 Karlsfeld, Germany
//  info@morethanip.com
//  http://www.morethanip.com
//  *************************************************************************
//  Designed by : Muhammad Anisur Rahman, Thomas Schrobenhauser
//  info@morethanip.com
//  *************************************************************************
//  Description : 40G MAC Reconciliation Sub-Layer (Rx)
//  Version     : $Id: rs_rx_64.v,v 1.4 2014/11/04 16:00:39 ts Exp $
//  *************************************************************************

module rs_rx_64 (
   reset_rxclk,
   enable_rx,
   xgmii_mode,
   xlgmii_rxclk,
   xlgmii_rxclk_ena,
   xlgmii_rxc,
   xlgmii_rxd,
   xlgmii_rxt0_next,
   rx_d,
   rx_dval,
   rx_start,
   rx_end,
   rx_final_size,
   frame_err,
   phy_err,
   rs_fault,
   lf_state,
   rf_state,
   li_state,
   rs_lowp
   );

input   reset_rxclk;                    //  Async active high reset
input   enable_rx;                      //  Enable state machines when PLLs are locked
input   xgmii_mode;                     //  XGMII mode enable (0=XLGMII, 1=XGMII)
input   xlgmii_rxclk;                   //  XLGMII receive clock
input   xlgmii_rxclk_ena;               //  XLGMII receive clock enable
input   [7:0] xlgmii_rxc;               //  XLGMII receive control
input   [63:0] xlgmii_rxd;              //  XLGMII receive data
input   xlgmii_rxt0_next;               //  XLGMII terminate on lane 0 in next word
output  [63:0] rx_d;                    //  Receive data
output  rx_dval;                        //  Receive data valid
output  rx_start;                       //  Start of Frame
output  rx_end;                         //  End of Frame
output  [2:0] rx_final_size;            //  Define size of final data word
output  frame_err;                      //  Frame error received
output  phy_err;                        //  Control code error
output  rs_fault;                       //  Link fault sequence detected (any)
output  lf_state;                       //  Local Fault
output  rf_state;                       //  Remote Fault
output  li_state;                       //  LinkInterruption fault
output  rs_lowp;                        //  Low Power Detection

reg     [63:0] rx_d;
reg     rx_dval;
reg     rx_start;
reg     rx_end;
reg     [2:0] rx_final_size;
reg     frame_err;
reg     phy_err;
reg     rs_fault;
reg     lf_state;
reg     rf_state;
reg     li_state;
wire    rs_lowp;

parameter STM_TYP_RINIT     = 2'b 00;
parameter STM_TYP_RCOUNT    = 2'b 01;
parameter STM_TYP_RFAULT    = 2'b 10;
parameter STM_TYP_RNEWFAULT = 2'b 11;

reg     [1:0] state;
reg     [1:0] nextstate;

wire    seq_detect;
wire    lowp_idle_detect;
reg     lowp_idle_detect_d;
wire    start_char;
wire    [7:0] is_data;
reg     data_valid;
wire    rx_end_int;
wire    [7:0] efd_det;
reg     [2:0] f_mod;
wire    [2:0] rx_final_size_int;
wire    error_det;
reg     error_store;
wire    [6:0] ctl_det;
wire    frame_err_int;
wire    phy_err_int;
wire    fault_seq;
wire    [1:0] seq_type;
reg     [1:0] last_seq_type;
reg     [1:0] seq_cnt;
reg     [6:0] col_cnt;
reg     xlgmii_rxt0;
wire    xgmii_mode_s;
wire    seq_lo;
wire    seq_hi;
wire    fault_lo;               //  fault sequence in lower column
wire    fault_hi;               //  fault sequence in upper column
wire    [1:0] seq_type_hi;
reg     rinit_rcount;           //  when RCOUNT goes into RINIT and higher column already contained a new sequence


//  Clock domain crossing
//  ---------------------
mtip_xsync #(1) U_SYNC (
          .data_in(xgmii_mode),
          .reset(reset_rxclk),
          .clk(xlgmii_rxclk),
          .data_s(xgmii_mode_s));

//  Detecting start of frame signal
//  -------------------------------
//  start of frame can follow TERM character immediately
assign start_char       = xlgmii_rxc[7:0] == 8'b 00000001 & xlgmii_rxd[7:0] == 8'h FB ? 1'b 1 : 1'b 0;

assign seq_detect       = xlgmii_rxc[7:0] == 8'b 00000001 & xlgmii_rxd[7:0] == 8'h 9c ? 1'b 1 : 1'b 0;
assign lowp_idle_detect = xlgmii_rxc[7:0] == 8'b 11111111 & xlgmii_rxd[63:0] == 64'h 0606060606060606 ? 1'b 1 : 1'b 0;

// Clause 49
assign seq_lo = xlgmii_rxc[3:0] == 4'b 0001 & xlgmii_rxd[7:0]   == 8'h 9c ? 1'b 1 : 1'b 0;
assign seq_hi = xlgmii_rxc[7:4] == 4'b 0001 & xlgmii_rxd[39:32] == 8'h 9c ? 1'b 1 : 1'b 0;

always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_1
   if (reset_rxclk == 1'b 1)
      begin
      lowp_idle_detect_d <= 1'b 0;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         lowp_idle_detect_d <= lowp_idle_detect;
         end
      end
   end

//  Low Power Detection
//  -------------------
assign rs_lowp = lowp_idle_detect_d;

//  Detecting end of frame signal
//  -----------------------------
//  "FE" is considered as data and is allowed to be forwarded with frame
assign is_data[0] = xlgmii_rxc[0] == 1'b 0 | xlgmii_rxc[0] == 1'b 1 & xlgmii_rxd[7:0]   == 8'h FE ? 1'b 1 : 1'b 0;
assign is_data[1] = xlgmii_rxc[1] == 1'b 0 | xlgmii_rxc[1] == 1'b 1 & xlgmii_rxd[15:8]  == 8'h FE ? 1'b 1 : 1'b 0;
assign is_data[2] = xlgmii_rxc[2] == 1'b 0 | xlgmii_rxc[2] == 1'b 1 & xlgmii_rxd[23:16] == 8'h FE ? 1'b 1 : 1'b 0;
assign is_data[3] = xlgmii_rxc[3] == 1'b 0 | xlgmii_rxc[3] == 1'b 1 & xlgmii_rxd[31:24] == 8'h FE ? 1'b 1 : 1'b 0;
assign is_data[4] = xlgmii_rxc[4] == 1'b 0 | xlgmii_rxc[4] == 1'b 1 & xlgmii_rxd[39:32] == 8'h FE ? 1'b 1 : 1'b 0;
assign is_data[5] = xlgmii_rxc[5] == 1'b 0 | xlgmii_rxc[5] == 1'b 1 & xlgmii_rxd[47:40] == 8'h FE ? 1'b 1 : 1'b 0;
assign is_data[6] = xlgmii_rxc[6] == 1'b 0 | xlgmii_rxc[6] == 1'b 1 & xlgmii_rxd[55:48] == 8'h FE ? 1'b 1 : 1'b 0;
assign is_data[7] = xlgmii_rxc[7] == 1'b 0 | xlgmii_rxc[7] == 1'b 1 & xlgmii_rxd[63:56] == 8'h FE ? 1'b 1 : 1'b 0;

//  frame valid indication excluding the period of start of frame indication
always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_2
   if (reset_rxclk == 1'b 1)
      begin
      data_valid <= 1'b 0;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         //  indicate valid frame data on input
         if (start_char == 1'b 1 & enable_rx == 1'b 1)
            begin
            data_valid <= 1'b 1;
            end
         else if (is_data != 8'b 11111111)
            begin
            //  any control character other than "FE" should end the inside frame indication flag
            data_valid <= 1'b 0;
            end
         end
      end
   end

assign rx_end_int = data_valid == 1'b 1 & is_data != 8'b 11111111 ? 1'b 1 : 1'b 0;

//  Processing modulo for the frame
//  -------------------------------
assign efd_det[0] = xlgmii_rxc[0] == 1'b 1 & xlgmii_rxd[7:0]   == 8'h FD ? 1'b 1 : 1'b 0;
assign efd_det[1] = xlgmii_rxc[1] == 1'b 1 & xlgmii_rxd[15:8]  == 8'h FD ? 1'b 1 : 1'b 0;
assign efd_det[2] = xlgmii_rxc[2] == 1'b 1 & xlgmii_rxd[23:16] == 8'h FD ? 1'b 1 : 1'b 0;
assign efd_det[3] = xlgmii_rxc[3] == 1'b 1 & xlgmii_rxd[31:24] == 8'h FD ? 1'b 1 : 1'b 0;
assign efd_det[4] = xlgmii_rxc[4] == 1'b 1 & xlgmii_rxd[39:32] == 8'h FD ? 1'b 1 : 1'b 0;
assign efd_det[5] = xlgmii_rxc[5] == 1'b 1 & xlgmii_rxd[47:40] == 8'h FD ? 1'b 1 : 1'b 0;
assign efd_det[6] = xlgmii_rxc[6] == 1'b 1 & xlgmii_rxd[55:48] == 8'h FD ? 1'b 1 : 1'b 0;
assign efd_det[7] = xlgmii_rxc[7] == 1'b 1 & xlgmii_rxd[63:56] == 8'h FD ? 1'b 1 : 1'b 0;

//  mode signal non-zero whenever data character received with non-data character on higher bytes
always @(xlgmii_rxc)
   begin : process_3
   if (xlgmii_rxc[7:0] == 8'b 10000000)
      begin
      f_mod = 3'b 111;
      end
   else if (xlgmii_rxc[6:0] == 7'b 1000000)
      begin
      f_mod = 3'b 110;
      end
   else if (xlgmii_rxc[5:0] == 6'b 100000)
      begin
      f_mod = 3'b 101;
      end
   else if (xlgmii_rxc[4:0] == 5'b 10000)
      begin
      f_mod = 3'b 100;
      end
   else if (xlgmii_rxc[3:0] == 4'b 1000)
      begin
      f_mod = 3'b 011;
      end
   else if (xlgmii_rxc[2:0] == 3'b 100)
      begin
      f_mod = 3'b 010;
      end
   else if (xlgmii_rxc[1:0] == 2'b 10)
      begin
      f_mod = 3'b 001;
      end
   else
      begin
      f_mod = 3'b 000;
      end
   end

//  mode signal calculated for every data character but valid only during the frame end indication
assign rx_final_size_int = rx_end_int == 1'b 1 ? f_mod : 3'b 000;

//  Verify correct termination
//  --------------------------
assign error_det = xlgmii_rxc[0] == 1'b 1 & xlgmii_rxd[7:0]   == 8'h FE |
                   xlgmii_rxc[1] == 1'b 1 & xlgmii_rxd[15:8]  == 8'h FE |
                   xlgmii_rxc[2] == 1'b 1 & xlgmii_rxd[23:16] == 8'h FE |
                   xlgmii_rxc[3] == 1'b 1 & xlgmii_rxd[31:24] == 8'h FE |
                   xlgmii_rxc[4] == 1'b 1 & xlgmii_rxd[39:32] == 8'h FE |
                   xlgmii_rxc[5] == 1'b 1 & xlgmii_rxd[47:40] == 8'h FE |
                   xlgmii_rxc[6] == 1'b 1 & xlgmii_rxd[55:48] == 8'h FE |
                   xlgmii_rxc[7] == 1'b 1 & xlgmii_rxd[63:56] == 8'h FE ? 1'b 1 : 1'b 0;

always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_4
   if (reset_rxclk == 1'b 1)
      begin
      error_store <= 1'b 0;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         //  error flag deasserted with end of frame or if start of a frame without "FE" character in the column
         if (start_char == 1'b 1 & error_det == 1'b 0 | rx_end_int == 1'b 1)
            begin
            error_store <= 1'b 0;
            end
         else if (error_det == 1'b 1)
            begin
            //  error flag asserted when "FE" character received
            error_store <= 1'b 1;
            end
         end
      end
   end

assign ctl_det[0] = xlgmii_rxc[0]        == 1'b 1 ? 1'b 1 : 1'b 0;
assign ctl_det[1] = (|(xlgmii_rxc[1:0])) == 1'b 1 ? 1'b 1 : 1'b 0;
assign ctl_det[2] = (|(xlgmii_rxc[2:0])) == 1'b 1 ? 1'b 1 : 1'b 0;
assign ctl_det[3] = (|(xlgmii_rxc[3:0])) == 1'b 1 ? 1'b 1 : 1'b 0;
assign ctl_det[4] = (|(xlgmii_rxc[4:0])) == 1'b 1 ? 1'b 1 : 1'b 0;
assign ctl_det[5] = (|(xlgmii_rxc[5:0])) == 1'b 1 ? 1'b 1 : 1'b 0;
assign ctl_det[6] = (|(xlgmii_rxc[6:0])) == 1'b 1 ? 1'b 1 : 1'b 0;

assign frame_err_int =  rx_end_int == 1'b 1 &
                       (efd_det == 8'b 00000000 |                                     //  Frame ends without frame end delimiter
                        efd_det[1] == 1'b 1 & ctl_det[0] == 1'b 1 |
                        efd_det[2] == 1'b 1 & ctl_det[1] == 1'b 1 |
                        efd_det[3] == 1'b 1 & ctl_det[2] == 1'b 1 |
                        efd_det[4] == 1'b 1 & ctl_det[3] == 1'b 1 |
                        efd_det[5] == 1'b 1 & ctl_det[4] == 1'b 1 |
                        efd_det[6] == 1'b 1 & ctl_det[5] == 1'b 1 |
                        efd_det[7] == 1'b 1 & ctl_det[6] == 1'b 1) ? 1'b 1 : 1'b 0;   //  TERM must be preceded by data only

//  well-known error control code was in frame
assign phy_err_int = error_store == 1'b 1 | error_det == 1'b 1 ? 1'b 1 : 1'b 0;

//  Fault State Machine
//  -------------------
always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_5
   if (reset_rxclk == 1'b 1)
      begin
      state <= STM_TYP_RINIT;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         state <= nextstate;
         end
      end
   end

// Clause 82
// Note: LinkInterruption not supported in Clause 82
assign fault_seq = xlgmii_rxc[7:0]   == 8'b 00000001 &
                   xlgmii_rxd[63:32] == 32'h 00000000 &
                  (xlgmii_rxd[31:24] == 8'h 01 |   // LF
                   xlgmii_rxd[31:24] == 8'h 02) &  // RF
                   xlgmii_rxd[23:0]  == 24'h 00009C ? 1'b 1 : 1'b 0;

// Clause 49
assign fault_lo = xlgmii_rxc[3:0]   == 4'b 0001 &
                 (xlgmii_rxd[31:24] == 8'h 01 |   // LF
                  xlgmii_rxd[31:24] == 8'h 02 |   // RF
                  xlgmii_rxd[31:24] == 8'h 03) &  // LinkInterruption
                  xlgmii_rxd[23:0]  == 24'h 00009C ? 1'b 1 : 1'b 0;

assign fault_hi = xlgmii_rxc[7:4]   == 4'b 0001 &
                 (xlgmii_rxd[63:56] == 8'h 01 |   // LF
                  xlgmii_rxd[63:56] == 8'h 02 |   // RF
                  xlgmii_rxd[63:56] == 8'h 03) &  // LinkInterruption
                  xlgmii_rxd[55:32] == 24'h 00009C ? 1'b 1 : 1'b 0;

//  lower 2 bits of byte 3 relevant only (sequence check for valid codes is done in fault_seq)
assign seq_type = xlgmii_rxd[25:24];

// Clause 49
assign seq_type_hi = xlgmii_rxd[57:56];

always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_6
   if (reset_rxclk == 1'b 1)
      begin
      last_seq_type <= 2'b 00;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         if (xgmii_mode_s == 1'b 0)   // Clause 82
            begin
            if (fault_seq == 1'b 1)
               begin
               last_seq_type <= seq_type;
               end
            end
         else   // xgmii_mode_s==1, Clause 49
            begin
            if (fault_lo == 1'b 1 & fault_hi == 1'b 0)
               begin
               last_seq_type <= seq_type;
               end
            else if (fault_hi == 1'b 1)
               begin
               last_seq_type <= seq_type_hi;
               end
            end
         end
      end
   end

always @(state or xgmii_mode_s or fault_seq or fault_lo or fault_hi or rinit_rcount or
         seq_cnt or seq_type or seq_type_hi or last_seq_type or col_cnt)
   begin : process_7
   case (state)
   STM_TYP_RINIT:
      begin
      if ((xgmii_mode_s == 1'b 0 & fault_seq == 1'b 1) |
          (xgmii_mode_s == 1'b 1 & (fault_lo == 1'b 1 | fault_hi == 1'b 1 | rinit_rcount == 1'b 1)))
         begin
         nextstate = STM_TYP_RCOUNT;
         end
      else
         begin
         nextstate = STM_TYP_RINIT;
         end
      end

   STM_TYP_RCOUNT:
      begin
      // current column has no fault sequence and previous 127 column had no fault sequence
      // which makes total of 128 column (for fault condition it should be less than 128)
      // so restart fault state machine
      if (xgmii_mode_s == 1'b 0)   // Clause 82
         begin
         if (fault_seq == 1'b 0 & col_cnt == 7'd 127)
            begin
            nextstate = STM_TYP_RINIT;
            end
         //  for the fourth fault of the same type, enter fault state
         else if (fault_seq == 1'b 1 & seq_cnt == 2'b 11 & seq_type == last_seq_type)
            begin
            nextstate = STM_TYP_RFAULT;
            end
         else if (fault_seq == 1'b 1 & seq_type != last_seq_type)
            begin
            nextstate = STM_TYP_RNEWFAULT;
            end
         else
            begin
            nextstate = STM_TYP_RCOUNT;
            end
         end
      else   // xgmii_mode_s==1, Clause 49
         begin
         if (((fault_lo == 1'b 0 & fault_hi == 1'b 0) & col_cnt[6:1] == 6'b 111111) |
             (fault_lo == 1'b 0 & col_cnt == 7'd 127))
            begin
            // 126 or 127 + 2 is > 128
            // 127 + 1 is > 128
            nextstate = STM_TYP_RINIT;
            end
         //  fault of different type
         else if ((fault_lo == 1'b 1 & seq_type != last_seq_type) |
                  (fault_hi == 1'b 1 & seq_type_hi != last_seq_type))
            begin
            nextstate = STM_TYP_RNEWFAULT;
            end
         //  for the fourth fault of the same type, enter fault state
         else if ((seq_cnt == 2'b 11 & (fault_lo == 1'b 1 | fault_hi == 1'b 1)) |
                  (seq_cnt == 2'b 10 & fault_lo == 1'b 1 & fault_hi == 1'b 1))
            begin
            nextstate = STM_TYP_RFAULT;
            end
         else
            begin
            nextstate = STM_TYP_RCOUNT;
            end
         end
      end

   STM_TYP_RFAULT:
      begin
      // current column has no fault sequence and previous 127 column had no fault sequence
      // which makes total of 128 column (for fault condition it should be less than 128)
      // so restart fault state machine
      if (xgmii_mode_s == 1'b 0)   // Clause 82
         begin
         if (fault_seq == 1'b 0 & col_cnt == 7'd 127)
            begin
            nextstate = STM_TYP_RINIT;
            end
         else if (fault_seq == 1'b 1 & seq_type != last_seq_type)
            begin
            nextstate = STM_TYP_RNEWFAULT;
            end
         else
            begin
            nextstate = STM_TYP_RFAULT;
            end
         end
      else   // xgmii_mode_s==1, Clause 49
         begin
         if (((fault_lo == 1'b 0 & fault_hi == 1'b 0) & col_cnt[6:1] == 6'b 111111) |
             (fault_lo == 1'b 0 & col_cnt == 7'd 127))
            begin
            // 126 or 127 + 2 is > 128
            // 127 + 1 is > 128
            nextstate = STM_TYP_RINIT;
            end
         //  fault of different type
         else if ((fault_lo == 1'b 1 & seq_type != last_seq_type) |
                  (fault_hi == 1'b 1 & seq_type_hi != last_seq_type))
            begin
            nextstate = STM_TYP_RNEWFAULT;
            end
         else
            begin
            nextstate = STM_TYP_RFAULT;
            end
         end
      end

   STM_TYP_RNEWFAULT:
      begin
      if (xgmii_mode_s == 1'b 0)   // Clause 82
         begin
         nextstate = STM_TYP_RCOUNT;
         end
      else   // xgmii_mode_s==1, Clause 49
         begin
         if ((fault_lo == 1'b 1 & seq_type != last_seq_type) |
             (fault_hi == 1'b 1 & seq_type_hi != last_seq_type))
            begin
            nextstate = STM_TYP_RNEWFAULT;
            end
         //  for the fourth fault of the same type, enter fault state
         else if (seq_cnt == 2'b 10 & fault_lo == 1'b 1 & fault_hi == 1'b 1)
            begin
            nextstate = STM_TYP_RFAULT;
            end
         else
            begin
            nextstate = STM_TYP_RCOUNT;
            end
         end
      end

   default:   // never reached
        begin
         nextstate = STM_TYP_RINIT;
        end
   endcase
   end

//  Counters for Fault State Machine
//  --------------------------------
//  four sequences of the same type should be counted to enter the fault state
always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_8
   if (reset_rxclk == 1'b 1)
      begin
      seq_cnt <= 2'b 00;   //  initialized with local fault type
      rinit_rcount <= 1'b 0;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         if (xgmii_mode_s == 1'b 0)   // Clause 82
            begin
            if (fault_seq == 1'b 1 & state == STM_TYP_RNEWFAULT & nextstate == STM_TYP_RCOUNT & seq_type == last_seq_type)
               begin
               //  two sequences should be counted, one before entering state RNEWFAULT and
               //  another for detecting another fault sequence of the same type while in the state RNEWFAULT
               seq_cnt <= 2'b 10;
               end
            else if (fault_seq == 1'b 1 & nextstate == STM_TYP_RCOUNT & seq_cnt != 2'b 11 |
                     state == STM_TYP_RNEWFAULT & nextstate == STM_TYP_RCOUNT)
               begin
               seq_cnt <= seq_cnt + 2'b 01;
               end
            else if (nextstate != STM_TYP_RCOUNT)
               begin
               seq_cnt <= 2'b 00;
               end

            rinit_rcount <= 1'b 0;
            end
         else   // xgmii_mode_s==1, Clause 49
            begin
            if (nextstate == STM_TYP_RCOUNT & fault_lo == 1'b 1 & fault_hi == 1'b 1 &
                seq_type == seq_type_hi)
               begin
               // two sequences of same type received
               seq_cnt <= seq_cnt + 2'b 10;
               end
            else if (nextstate == STM_TYP_RCOUNT & ((fault_lo == 1'b 1 & fault_hi == 1'b 0) |
                     (fault_lo == 1'b 0 & fault_hi == 1'b 1)))
               begin
               // one sequence received
               seq_cnt <= seq_cnt + 2'b 01;
               end
            else if (nextstate == STM_TYP_RNEWFAULT)
               begin
               if (fault_lo == 1'b 1 & fault_hi == 1'b 1 & seq_type == seq_type_hi)
                  begin
                  // two sequences of same type received
                  seq_cnt <= 2'b 10;
                  end
               else
                  begin
                  // implicit: one sequence received
                  seq_cnt <= 2'b 01;
                  end
               end
            else if ((state == STM_TYP_RCOUNT | state == STM_TYP_RFAULT) &
                     nextstate == STM_TYP_RINIT & fault_hi == 1'b 1)
               begin
               // don't lose sequence if immediately following after 128
               seq_cnt <= 2'b 01;
               end
            else if (nextstate != STM_TYP_RCOUNT)
               begin
               seq_cnt <= 2'b 00;
               end

            if ((state == STM_TYP_RCOUNT | state == STM_TYP_RFAULT) &
                nextstate == STM_TYP_RINIT & fault_hi == 1'b 1)
               begin
               // when RCOUNT goes into RINIT and higher column already contained a new sequence,
               // go back to RCOUNT immediately
               rinit_rcount <= 1'b 1;
               end
            else
               begin
               rinit_rcount <= 1'b 0;
               end
            end
         end
      end
   end

//  column count between two consecutive fault sequences
always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_9
   if (reset_rxclk == 1'b 1)
      begin
      col_cnt <= {7{1'b 0}};
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         if (xgmii_mode_s == 1'b 0)   // Clause 82
            begin
            if (fault_seq == 1'b 1)
               begin
               col_cnt <= {7{1'b 0}};
               end
            else if ((nextstate == STM_TYP_RFAULT | nextstate == STM_TYP_RCOUNT) & (col_cnt < 7'd 127))
               begin
               col_cnt <= col_cnt + 7'd 1;
               end
            end
         else   // xgmii_mode_s==1, Clause 49
            begin
            if (fault_hi == 1'b 1)
               begin
               col_cnt <= {7{1'b 0}};
               end
            else if (fault_lo == 1'b 1)   // implicit: and fault_hi==0
               begin
               col_cnt <= 7'd 1;   // count 1 non-fault column
               end
            else if (nextstate == STM_TYP_RFAULT | nextstate == STM_TYP_RCOUNT)
               begin
               if (col_cnt < 7'd 126)
                  begin
                  col_cnt <= col_cnt + 7'd 2;   // add 2 non-fault columns
                  end
               else if (col_cnt == 7'd 126)
                  begin
                  col_cnt <= col_cnt + 7'd 1;   // add 1, saturate at 127
                  end
               end
            end
         end
      end
   end

//  Create Fault Indicators
//  -----------------------
always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_10
   if (reset_rxclk == 1'b 1)
      begin
      lf_state <= 1'b 0;
      rf_state <= 1'b 0;
      li_state <= 1'b 0;
      rs_fault <= 1'b 0;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         //  next is RFAULT
         //  or next is RNEWFAULT, but we went through the state of RFAULT because lower column
         //  had a good fault sequence, incrementing seq_cnt to 4 (e.g. 4RF+1LF)
         if ((nextstate == STM_TYP_RFAULT) |
             (xgmii_mode_s == 1'b 1 & state == STM_TYP_RCOUNT & nextstate == STM_TYP_RNEWFAULT &
              seq_cnt == 2'b 11 & fault_lo == 1'b 1 & seq_type == last_seq_type))
            begin
            //  Local Fault
            if (last_seq_type == 2'b 01)
               begin
               lf_state <= 1'b 1;
               end
            else
               begin
               lf_state <= 1'b 0;
               end

            //  Remote Fault
            if (last_seq_type == 2'b 10)
               begin
               rf_state <= 1'b 1;
               end
            else
               begin
               rf_state <= 1'b 0;
               end

            //  LinkInterruption Fault
            if (last_seq_type == 2'b 11)
               begin
               li_state <= 1'b 1;
               end
            else
               begin
               li_state <= 1'b 0;
               end
            end
         else if (state == STM_TYP_RINIT)
            begin
            lf_state <= 1'b 0;
            rf_state <= 1'b 0;
            li_state <= 1'b 0;
            end

         //  indicate fault sequence reception within frame
         if (data_valid == 1'b 1 & ((xgmii_mode_s == 1'b 0 & seq_detect == 1'b 1) |
             (xgmii_mode_s == 1'b 1 & (seq_lo == 1'b 1 | seq_hi == 1'b 1))))
            begin
            rs_fault <= 1'b 1;
            end
         else
            begin
            rs_fault <= 1'b 0;
            end
         end
      end
   end

// Output Generation
// -----------------
always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_11
   if (reset_rxclk == 1'b 1)
      begin
      xlgmii_rxt0   <= 1'b 0;
      rx_d          <= {64{1'b 0}};
      rx_start      <= 1'b 0;
      rx_end        <= 1'b 0;
      rx_final_size <= 3'b 000;
      frame_err     <= 1'b 0;
      phy_err       <= 1'b 0;
      end
   else
      begin
      if (xlgmii_rxclk_ena == 1'b 1)
         begin
         xlgmii_rxt0 <= xlgmii_rxt0_next;
         rx_d <= xlgmii_rxd;

         //  start of frame should not be same time of end of frame
         if (xlgmii_rxt0_next == 1'b 0 & rx_end_int == 1'b 0 & enable_rx == 1'b 1)
            begin
            rx_start <= start_char;
            end
         else
            begin
            rx_start <= 1'b 0;
            end

         //  end of frame should not be same time of start of frame
         if (xlgmii_rxt0_next == 1'b 1 & rx_end_int == 1'b 0 & start_char == 1'b 0)
            begin
            //  eof on next column 0
            rx_end        <= 1'b 1;
            rx_final_size <= 3'b 000;   // full word
            frame_err     <= frame_err_int;
            phy_err       <= phy_err_int;
            end
         else if (xlgmii_rxt0 == 1'b 0 & rx_end_int == 1'b 1 & start_char == 1'b 0)
            begin
            rx_end        <= 1'b 1;
            rx_final_size <= rx_final_size_int;
            frame_err     <= frame_err_int;
            phy_err       <= phy_err_int;
            end
         else
            begin
            rx_end        <= 1'b 0;
            rx_final_size <= 3'b 000;
            frame_err     <= 1'b 0;
            phy_err       <= 1'b 0;
            end
         end
      end
   end

// Data Valid Generation
// ---------------------

always @(posedge reset_rxclk or posedge xlgmii_rxclk)
   begin : process_12
   if (reset_rxclk == 1'b 1)
      begin
      rx_dval <= 1'b 0;
      end
   else
      begin
      rx_dval <= xlgmii_rxclk_ena;
      end
   end


endmodule // module rs_rx_64
